package imp

import (
	sqlc "bgs/db/sqlc"
	storeEndorseRequestGrpc "bgs/grpc/gen/service/store_endorse_request"
	"bgs/grpc/gen/shared/message"
	"bgs/util"
	"bytes"
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

/****************************************************************************************/
/*                               store_endorse_request entity of helper                 */
/****************************************************************************************/

func transformStoreEndorseRequestEntityToPb(StoreEndorseRequest sqlc.StoreEndorseRequest) *storeEndorseRequestGrpc.StoreEndorseRequestEntity {
	return &storeEndorseRequestGrpc.StoreEndorseRequestEntity{
		Id:          StoreEndorseRequest.ID,
		StoreId:     StoreEndorseRequest.StoreID,
		UserId:      StoreEndorseRequest.UserID,
		Requested:   sqlc.GoTimeToPBTimestamp(StoreEndorseRequest.Requested),
		Audited:     sqlc.GoTimeToPBTimestamp(StoreEndorseRequest.Audited.Time),
		ApplyFields: string(StoreEndorseRequest.ApplyFields),
		AuditResult: StoreEndorseRequest.AuditResult,
	}
}

/****************************************************************************************/
/*                               store_endorse_request entity of cmd                    */
/****************************************************************************************/

// ApplyStoreEndorseRequest 申请门店代言请求
func (s *StoreAPIService) ApplyStoreEndorseRequest(ctx context.Context, req *storeEndorseRequestGrpc.ApplyStoreEndorseRequestRequest) (res *storeEndorseRequestGrpc.ApplyStoreEndorseRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("store_endorse_requestImp->ApplyStoreEndorseRequest:%v", req)

	res = &storeEndorseRequestGrpc.ApplyStoreEndorseRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	userID := req.UserId
	storeID := req.StoreId
	storePtr, err := s.storeService.GetStorePtr(ctx, q, storeID)
	if err != nil {
		return
	}
	// 1 判断代言设置
	storeEndorsement, sqlErr := q.GetStoreEndorsementByStoreID(ctx, req.StoreId)
	if sqlErr != nil {
		if sql.ErrNoRows != sqlErr {
			err = sqlErr
		} else {
			err = fmt.Errorf("门店未开启招募代言人 brandID:%d", req.StoreId)
		}
		return
	}
	// 查到代言设置
	if !storeEndorsement.IsOpen {
		err = fmt.Errorf("门店关闭了招募代言人 brandID:%d", req.StoreId)
		return
	}

	if storeEndorsement.UserStratified == string(sqlc.EmUserStratificationConsumer) {
		// 检查消息记录
		// 临时
		err = fmt.Errorf("未实现对于用户的门店最低消费金额计算 userID:%d", req.StoreId)
		return
	}

	if !storeEndorsement.NeedApplyInfo {
		err = fmt.Errorf("没有任何申请信息不可能存在%d", req.StoreId)
		return
	}

	var oApplyFields map[string]string
	if decodeErr := json.NewDecoder(strings.NewReader(req.ApplyFields)).Decode(&oApplyFields); decodeErr != nil {
		err = fmt.Errorf("无法解析申请信息: %v", decodeErr)
		return
	}
	fields := storeEndorsement.ApplyInfoFields
	for _, field := range fields {
		if oApplyFields[field] == "" {
			err = fmt.Errorf("缺少申请信息: %s", field)
			return
		}
	}

	// 2 判断是否申请用户已经是门店的代言人
	storeSpokesmanPtr, getErr := s.spokesmanService.GetStoreSpokesmanPtr(ctx, q, userID, storeID)
	if getErr != nil {
		if sql.ErrNoRows != getErr {
			err = getErr
			return
		}
		slog.Infof("还不是门店代言人,继续")
	} else {
		// 查到代言人了
		if storeSpokesmanPtr.Status == string(sqlc.EmRecordStatusNormal) {
			err = fmt.Errorf("已经是门店代言人了userID:%d,brandID:%d", userID, storeID)
			return
		}
	}

	// 没找到代言人或者代言人处于作废状态,需要继续寻找是否有相同的申请记录
	pendingRequestCount, sqlErr := s.dao.Q.CountPendingStoreEndorseRequestByStoreIDAndUserID(ctx,
		sqlc.CountPendingStoreEndorseRequestByStoreIDAndUserIDParams{
			UserID:  userID,
			StoreID: storeID,
		},
	)
	if sqlErr != nil {
		err = sqlErr
		return
	}
	slog.Infof("寻找是否有相同的申请记录=>%d", pendingRequestCount)

	if pendingRequestCount > 0 {
		err = fmt.Errorf("已经存在代言人申请记录userID:%d,brandID:%d", userID, storeID)
		return
	}
	var needSendNotify bool
	var storeEndorseRequest sqlc.StoreEndorseRequest
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		// 3 创建代言申请,如果是自动审核,设置门店代言关系
		storeEndorseRequest, err = q.CreateStoreEndorseRequest(ctx, sqlc.CreateStoreEndorseRequestParams{
			StoreID:     storeID,
			UserID:      userID,
			ApplyFields: []byte(req.ApplyFields),
			Audited:     util.IfThenElse(storeEndorsement.IsAutoApproved, sqlc.NTimeFromTime(time.Now()), sql.NullTime{}).(sql.NullTime),
			AuditResult: string(util.IfThenElse(storeEndorsement.IsAutoApproved, sqlc.EmAuditResultApproved, sqlc.EmAuditResultPending).(sqlc.EmAuditResult)),
		})
		if err != nil {
			return err
		}
		slog.Infof("创建门店代言申请成功=>", storeEndorseRequest.ID)
		// 此处brandEndorseRequest.AuditResult只有pending和approved两种结果
		// userID := storeEndorseRequest.UserID
		brandID := storePtr.BrandID
		if storeEndorseRequest.AuditResult == string(sqlc.EmAuditResultApproved) {
			// 插入/更新门店代言关系
			endorseObjectKey := fmt.Sprintf("%d-%d", brandID, storeID)
			_, err = q.UpsertSpokesman(ctx, sqlc.UpsertSpokesmanParams{
				UserID:           userID,
				BrandID:          brandID,
				StoreID:          sqlc.NInt64FromInt64(storeID),
				EndorseObjectKey: endorseObjectKey,
				AliasName:        oApplyFields[string(sqlc.EmStoreEndorseApplyFieldNickName)],
				Became:           time.Now(),
			})
			if err != nil {
				return err
			}
			slog.Infof("s0 插入门店代言人 ok")

			err = s.userService.UpdateUserStatSinceBecomeStoreSpokesman(ctx, q, userID)
			if err != nil {
				return err
			}
			slog.Infof("s1 更新用户统计 ok")

			err = s.storeService.UpdateStoreStatSpokesmanCountSinceUpsertStoreSpokesman(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新门店统计的spokesman_count ok")

			needSendNotify = true
		} else {
			err = s.storeService.UpdateStoreStatEndorseRequestCountSinceCreateStoreEndorsePendingRequest(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新门店统计的endorse_request_to_audit_count ok")
		}
		return
	})
	if err != nil {
		return
	}

	if needSendNotify {
		notifyParam, genErr := s.storeService.GenEndorseRequestAuditedNotifyMessage(ctx, s.dao.Q, storeEndorseRequest.ID)
		if genErr != nil {
			slog.Errorf("ApplyStoreEndorseRequest 门店生成代言人审核结果消息失败:%s", genErr.Error())
			// 不影响主流程因此不赋值给err
		}
		sendErr := s.wxpMinaService.SendNotify(ctx, &notifyParam)
		if sendErr != nil {
			slog.Errorf("ApplyStoreEndorseRequest 发送mina代言人审核结果提醒失败:%s", sendErr.Error())
		}
	}
	res.StoreEndorseRequest = transformStoreEndorseRequestEntityToPb(storeEndorseRequest)
	return
}

// AuditStoreEndorseRequest 审核门店代言请求
func (s *StoreAPIService) AuditStoreEndorseRequest(ctx context.Context, req *storeEndorseRequestGrpc.AuditStoreEndorseRequestRequest) (res *storeEndorseRequestGrpc.AuditStoreEndorseRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("store_endorse_requestImp->AuditStoreEndorseRequest:%v", req)
	res = &storeEndorseRequestGrpc.AuditStoreEndorseRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	if req.AuditResult == string(sqlc.EmAuditResultPending) {
		err = fmt.Errorf("无效的审核结果:%s", req.AuditResult)
		return
	}

	var needSendNotify bool
	var storeEndorseRequest sqlc.StoreEndorseRequest
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		storeEndorseRequest, err = q.UpdateStoreEndorseRequest(ctx, sqlc.UpdateStoreEndorseRequestParams{
			ID:          req.Id,
			Audited:     sqlc.NTimeFromTime(sqlc.PBTimestampToGoTime(req.Audited)),
			AuditResult: req.AuditResult,
		})
		if err != nil {
			return err
		}
		var oApplyFields map[sqlc.EmBrandEndorseApplyField]string
		if decodeErr := json.NewDecoder(bytes.NewReader(storeEndorseRequest.ApplyFields)).Decode(&oApplyFields); err != nil {
			err = fmt.Errorf("无法解析申请信息: %s", decodeErr)
			return
		}

		if storeEndorseRequest.AuditResult == string(sqlc.EmAuditResultApproved) {
			// 插入/更新门店代言关系
			userID := storeEndorseRequest.UserID
			storeID := storeEndorseRequest.StoreID
			storePtr, err2 := s.storeService.GetStorePtr(ctx, q, storeID)
			if err2 != nil {
				err = err2
				return
			}
			brandID := storePtr.BrandID
			endorseObjectKey := fmt.Sprintf("%d-%d", brandID, storeID)
			_, err = q.UpsertSpokesman(ctx, sqlc.UpsertSpokesmanParams{
				UserID:           userID,
				BrandID:          brandID,
				StoreID:          sqlc.NInt64FromInt64(storeID),
				EndorseObjectKey: endorseObjectKey,
				AliasName:        oApplyFields[sqlc.EmBrandEndorseApplyFieldNickName],
				Became:           time.Now(),
			})
			if err != nil {
				return err
			}
			err = s.userService.UpdateUserStatSinceBecomeStoreSpokesman(ctx, q, userID)
			if err != nil {
				return err
			}
			slog.Infof("s1 更新用户统计 ok")

			err = s.storeService.UpdateStoreStatSpokesmanCountSinceUpsertStoreSpokesman(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新门店统计的spokesman_count ok")

		} else if storeEndorseRequest.AuditResult == string(sqlc.EmAuditResultApproved) {
			// 拒绝,暂时什么都不做
			slog.Infof("审核代言人拒绝")
		}
		needSendNotify = true
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if needSendNotify {
		notifyParam, genErr := s.storeService.GenEndorseRequestAuditedNotifyMessage(ctx, s.dao.Q, storeEndorseRequest.ID)
		if genErr != nil {
			slog.Errorf("AuditStoreEndorseRequest 生成代言人审核结果消息失败:%s", genErr.Error())
			// 不影响主流程因此不赋值给err
		}
		sendErr := s.wxpMinaService.SendNotify(ctx, &notifyParam)
		if sendErr != nil {
			slog.Errorf("AuditStoreEndorseRequest 发送mina代言人审核结果提醒失败:%s", sendErr.Error())
		}
	}
	res.StoreEndorseRequest = transformStoreEndorseRequestEntityToPb(storeEndorseRequest)
	return
}

/****************************************************************************************/
/*                               store_endorse_request entity of query                  */
/****************************************************************************************/

// GetStoreEndorseRequest 获取单个门店代言请求
func (s *StoreAPIService) GetStoreEndorseRequest(ctx context.Context, req *storeEndorseRequestGrpc.GetStoreEndorseRequestRequest) (res *storeEndorseRequestGrpc.GetStoreEndorseRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("store_endorse_requestImp->GetStoreEndorseRequest:%v", req)
	res = &storeEndorseRequestGrpc.GetStoreEndorseRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	brandEndorseRequest, err := s.dao.Q.GetStoreEndorseRequest(ctx, req.Id)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.StoreEndorseRequest = transformStoreEndorseRequestEntityToPb(brandEndorseRequest)
	return
}

// GetStoreEndorseRequestByStoreIDAndUserID 根据门店ID和用户ID获取最新的代言请求
func (s *StoreAPIService) GetStoreEndorseRequestByStoreIDAndUserID(ctx context.Context, req *storeEndorseRequestGrpc.GetStoreEndorseRequestByStoreIDAndUserIDRequest) (res *storeEndorseRequestGrpc.GetStoreEndorseRequestByStoreIDAndUserIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("store_endorse_requestImp->GetStoreEndorseRequestByStoreIDAndUserID:%v", req)
	res = &storeEndorseRequestGrpc.GetStoreEndorseRequestByStoreIDAndUserIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	userID := req.UserId
	storeID := req.StoreId

	brandEndorseRequest, sqlErr := q.GetStoreEndorseRequestByStoreIDAndUserID(ctx, sqlc.GetStoreEndorseRequestByStoreIDAndUserIDParams{
		StoreID: storeID,
		UserID:  userID,
	})
	if sqlErr != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    util.Int32IfThenElse(sql.ErrNoRows == sqlErr, 404, 400),
			Msg:     sqlErr.Error(),
		}
		return
	}
	res.StoreEndorseRequest = transformStoreEndorseRequestEntityToPb(brandEndorseRequest)
	return
}

/****************************************************************************************/
/*                               store_endorse_requestJoins entity of helper            */
/****************************************************************************************/

func transformStoreEndorseRequestWithUserInfoEntityToPb(o sqlc.ListStoreEndorseRequestWithUserInfosByStoreIDAndAuditResultsRow) *storeEndorseRequestGrpc.StoreEndorseRequestWithUserInfoEntity {
	return &storeEndorseRequestGrpc.StoreEndorseRequestWithUserInfoEntity{
		Id:          o.ID,
		StoreId:     o.StoreID,
		UserId:      o.UserID,
		Requested:   sqlc.GoTimeToPBTimestamp(o.Requested),
		Audited:     sqlc.GoTimeToPBTimestamp(o.Audited.Time),
		ApplyFields: string(o.ApplyFields),
		AuditResult: o.AuditResult,
		UserPic:     o.UserPic.String,
	}
}

func mapStoreEndorseRequestWithUserInfoEntityToPb(list []sqlc.ListStoreEndorseRequestWithUserInfosByStoreIDAndAuditResultsRow, f func(sqlc.ListStoreEndorseRequestWithUserInfosByStoreIDAndAuditResultsRow) *storeEndorseRequestGrpc.StoreEndorseRequestWithUserInfoEntity) []*storeEndorseRequestGrpc.StoreEndorseRequestWithUserInfoEntity {
	r := make([]*storeEndorseRequestGrpc.StoreEndorseRequestWithUserInfoEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               store_endorse_requestJoins entity of query                  */
/****************************************************************************************/

// ListStoreEndorseRequestWithUserInfosByStoreID  根据门店ID获取代言请求+用户信息
func (s *StoreAPIService) ListStoreEndorseRequestWithUserInfosByStoreID(ctx context.Context, req *storeEndorseRequestGrpc.ListStoreEndorseRequestWithUserInfosByStoreIDRequest) (res *storeEndorseRequestGrpc.ListStoreEndorseRequestWithUserInfosByStoreIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("store_endorse_requestImp->ListStoreEndorseRequestWithUserInfosByStoreID:%v", req)

	res = &storeEndorseRequestGrpc.ListStoreEndorseRequestWithUserInfosByStoreIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	storeID := req.StoreId
	auditResults := req.AuditResults

	total, err := q.CountStoreEndorseRequestWithUserInfosByStoreIDAndAuditResults(ctx, sqlc.CountStoreEndorseRequestWithUserInfosByStoreIDAndAuditResultsParams{
		Created:      sqlc.PBTimestampToGoTime(req.Ts),
		StoreID:      storeID,
		AuditResults: auditResults,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	brandEndorseRequests, err := q.ListStoreEndorseRequestWithUserInfosByStoreIDAndAuditResults(ctx, sqlc.ListStoreEndorseRequestWithUserInfosByStoreIDAndAuditResultsParams{
		Limit:        req.Limit,
		Offset:       req.Offset,
		Created:      sqlc.PBTimestampToGoTime(req.Ts),
		StoreID:      storeID,
		AuditResults: auditResults,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.StoreEndorseRequestWithUserInfos = mapStoreEndorseRequestWithUserInfoEntityToPb(brandEndorseRequests, transformStoreEndorseRequestWithUserInfoEntityToPb)
	return
}
